package org.groupg.practice;

import cn.hutool.core.lang.Console;
import io.github.resilience4j.bulkhead.Bulkhead;
import io.github.resilience4j.bulkhead.BulkheadFullException;
import io.github.resilience4j.bulkhead.ThreadPoolBulkhead;
import io.github.resilience4j.circuitbreaker.CallNotPermittedException;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.decorators.Decorators;
import io.github.resilience4j.retry.Retry;
import io.github.resilience4j.timelimiter.TimeLimiter;

import java.io.IOException;
import java.time.Duration;
import java.util.concurrent.*;
import java.util.function.Supplier;

import static java.util.Arrays.asList;

public class RetryExample {

    public static void main(String[] args) {
        // 使用默认配置创建熔断器
        CircuitBreaker circuitBreaker = CircuitBreaker
                .ofDefaults("backendService");

        // 创建默认配置的重试策略
        // 最多重试3次，每次重试间隔500毫秒
        Retry retry = Retry
                .ofDefaults("backendService");

        // 使用默认配置创建舱壁隔离（Bulkhead）
        Bulkhead bulkhead = Bulkhead
                .ofDefaults("backendService");

        Supplier<String> supplier = (()->{
                    try {
                        doSomething();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    return null;
                });

        // 将原始Supplier用舱壁隔离、熔断器和重试进行组合装饰
        // **注意：需要引入 resilience4j-all 依赖
        Supplier<String> decoratedSupplier = Decorators.ofSupplier(supplier)
                .withCircuitBreaker(circuitBreaker)
                .withBulkhead(bulkhead)
                .withRetry(retry)
                .decorate();


        // 当不需要装饰lambda表达式，仅需通过熔断器执行保护时
        String result = circuitBreaker
                .executeSupplier(()->{
                    try {
                        return doSomething();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    return null;
                });

//        decoratedSupplier.

        // 创建线程池隔离仓（异步执行的舱壁隔离）
        ThreadPoolBulkhead threadPoolBulkhead = ThreadPoolBulkhead
                .ofDefaults("backendService");

        // 需要调度器来为非阻塞的CompletableFuture设置超时
        // 创建定时任务线程池（3个线程）
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
        // 创建限时器（1秒超时）
        TimeLimiter timeLimiter = TimeLimiter.of(Duration.ofSeconds(1));

        // 构建带容错保护的异步调用链：
        // 1. 使用线程池隔离仓执行
        // 2. 添加1秒超时限制
        // 3. 添加熔断器保护
        // 4. 配置降级策略（针对超时、熔断拒绝、隔离仓满等异常返回恢复值）
        CompletableFuture<String> future = Decorators.ofSupplier(supplier)
                .withThreadPoolBulkhead(threadPoolBulkhead)
                .withTimeLimiter(timeLimiter, scheduledExecutorService)
                .withCircuitBreaker(circuitBreaker)
                .withFallback(asList(TimeoutException.class,
                                CallNotPermittedException.class,
                                BulkheadFullException.class),
                        throwable -> "Hello from Recovery")
                .get().toCompletableFuture();
        try {
            Console.log(future.get(2, TimeUnit.SECONDS));
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            throw new RuntimeException(e);
        }
    }

    // 模拟可能失败的操作（实际业务方法）
    private static String doSomething() throws IOException {
        double random = Math.random();
        System.out.println("执行操作，随机值: " + random);
        if (random < 0.8) { // 80%概率失败
            System.out.println("操作失败！");
            throw new IOException("模拟IO异常");

        }
        System.out.println("操作成功！");
        return String.format("%f0.00", random);
    }
}